﻿using System.Collections.Generic;
using System.Threading;
using JetBrains.Annotations;

namespace Rsdn.Janus
{
    using System;
    using System.Windows.Forms;
    using SmartApp;
    using TreeGrid;

    /// <summary>
    /// Управляет исходящими.
    /// </summary>
    [Service(typeof (IOutboxManager))]
    public class OutboxManager : OutboxManagerBase, IOutboxManager, IKeyedNode
    {
        protected RateMarkCollection _rateMarks;
        protected DownloadTopicCollection _downloadTopics;

        // Old
        // private const int _bugReportTopicId = 1099540;
        // New (from r830)
        private const int _bugReportTopicId = 2855740;
        private const int _bugReportForumId = 30;
        Dictionary<int,bool> _lockedMessageIds = new Dictionary<int, bool>();
        private int _lockCount = 0;

        public OutboxManager(IServiceProvider serviceProvider) : base(serviceProvider)
        {
            _rateMarks = new RateMarkCollection(serviceProvider, this);
            _downloadTopics = new DownloadTopicCollection(serviceProvider, this);
            _newMessages = new NewMessageCollection(serviceProvider, this, false);

            _collections = new ITreeNode[]
                               {
                                   _newMessages, _rateMarks, _downloadTopics
                               };
        }

        /// <summary>
        /// Inits this instance.
        /// </summary>
        public override void Init()
        {
            ISynchronizer synchronizer = ServiceProvider.GetRequiredService<ISynchronizer>();

            synchronizer.EndSync.Subscribe(
                arg =>
                {
                    _newMessages.Refresh();
                    _rateMarks.Refresh();
                    _downloadTopics.Refresh();
                });
        }

        private DownloadTopicCollection DownloadTopics
        {
            get { return _downloadTopics; }
        }


 

        #region IKeyedNode Members

        /// <summary>
        /// Уникальный ключ в пределах одного уровня иерархии .
        /// </summary>
        /// <value></value>
        string IKeyedNode.Key
        {
            get { return GetType().Name; }
        }

        #endregion

        #region IOutboxManager Members

        /// <summary>
        /// Выводит окно с запросом на добавление темы в очередь загрузки.
        /// </summary>
        /// <param name="mid">ID сообщения</param>
        public void AddTopicForDownloadWithConfirm(int mid)
        {
            DialogResult result = MessageBox.Show(
                SR.MessageAbsentMsgBoxMessage,
                SR.MessageAbsentMsgBoxTitle,
                MessageBoxButtons.YesNo,
                MessageBoxIcon.Question,
                MessageBoxDefaultButton.Button1);

            if (result != DialogResult.Yes)
            {
                return;
            }

            string hint = string.Format(SR.Forum.DownloadTopicHint, mid);
            DownloadTopics.Add(SR.Forum.DownloadTopicClickSource, mid, hint);
        }

        /// <summary>
        /// Поместить сообщение в очередь загрузки.
        /// </summary>
        /// <param name="mid">The mid.</param>
        public void AddTopicForDownload(int mid)
        {
            string hint = string.Format(SR.Forum.DownloadTopicHint, mid);
            DownloadTopics.Add(SR.Forum.DownloadTopicManualSource, mid, hint);
        }


        /// <summary>
        /// Adds the bug report.
        /// </summary>
        /// <param name="bugName">Name of the bug.</param>
        /// <param name="bugDescription">The bug description.</param>
        /// <param name="stackTrace">The stack trace.</param>
        /// <param name="showEditor">if set to <c>true</c> [show editor].</param>
        public void AddBugReport(string bugName, string bugDescription, string stackTrace, bool showEditor)
        {
            string bugText = string.Format(
                SR.Outbox.BugReportTemplate, 
                bugName, 
                bugDescription, 
                ApplicationInfo.NameWithVersion, 
                Config.Instance.DbDriver, 
                stackTrace);

            MessageInfo msgInfo = new MessageInfo(_bugReportForumId, _bugReportTopicId, bugName, bugText);

            if (showEditor)
            {
                MessageEditor.EditMessage(ServiceProvider, MessageFormMode.Add, msgInfo);
            }
            else
            {
                NewMessages.Add(msgInfo);
            }
        }

        /// <summary>
        /// Gets the locked message ids.
        /// </summary>
        /// <returns></returns>
        public Dictionary<int, bool> GetLockedMessageIds()
        {
            return _lockedMessageIds;
        }

        /// <summary>
        /// Locks the message.
        /// </summary>
        /// <param name="id">The id.</param>
        public void LockMessage(int id)
        {
            _lockedMessageIds[id] = true;
        }

        /// <summary>
        /// Releases the message.
        /// </summary>
        /// <param name="id">The id.</param>
        public void ReleaseMessage(int id)
        {
            _lockedMessageIds.Remove(id);
        }

        public bool IsAllowedEditMessages
        {
            get { return _lockCount == 0; }
        }

        public void LockMessageEditing()
        {
            Interlocked.Increment(ref _lockCount);
        }

        public void ReleaseMessageEditing()
        {
            // It could be additional lock used but wrong release usage are not expected
            if (_lockCount > 0)
            {
                Interlocked.Decrement(ref _lockCount);
            }
        }

        IOutboxRateCollection IOutboxManager.RateMarks
        {
            get { return RateMarks; }
        }

        IDownloadTopicCollection IOutboxManager.DownloadTopics
        {
            get { return _downloadTopics; }
        }

        #endregion

        private RateMarkCollection RateMarks
        {
            get { return _rateMarks; }
        }

        /// <summary>
        /// Gets the outbox form.
        /// </summary>
        /// <value>The outbox form.</value>
        [NotNull]
        public override IOutboxForm OutboxForm
        {
            get
            {
                if (_outboxForm == null)
                {
                    lock (_formLockFlag)
                    {
                        if (_outboxForm == null)
                        {
                            _outboxForm = new OutboxDummyForm(ServiceProvider, this);
                        }
                    }
                }

                return _outboxForm;
            }
        }

        IOutboxForm IOutboxManagerBase.OutboxForm
        {
            get { return OutboxForm; }
        }
    }
}